home *** CD-ROM | disk | FTP | other *** search
/ Revista do CD-ROM 101 / CD-ROM 101.iso / compl / maya5ple / Install_MayaPLE5_English.exe / Maya / Data1.cab / offsetSurfaceUsingLoft.mel < prev    next >
Encoding:
Text File  |  2003-07-17  |  8.6 KB  |  249 lines

  1. // Copyright (C) 1997-2002 Alias|Wavefront,
  2. // a division of Silicon Graphics Limited.
  3. //
  4. // The information in this file is provided for the exclusive use of the
  5. // licensees of Alias|Wavefront.  Such users have the right to use, modify,
  6. // and incorporate this code into other products for purposes authorized
  7. // by the Alias|Wavefront license agreement, without fee.
  8. //
  9. // ALIAS|WAVEFRONT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  10. // INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  11. // EVENT SHALL ALIAS|WAVEFRONT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  12. // CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  13. // DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  14. // TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  15. // PERFORMANCE OF THIS SOFTWARE.
  16. //
  17. // offsetSurfaceUsingLoft - offsets one or more NURBS surfaces
  18. // 
  19. // Usage: 
  20. //   offsetSurfaceUsingLoft(float <distance>, int <nsamples>); 
  21. //
  22. //  where: <distance> is distance to offset the surface (can be negative) 
  23. //         <nsamples> is the number of points per surface
  24. //                      patch that are sampled
  25. // 
  26. // How it works:
  27. //   1. Samples points along V isoparms and build degree 1 curves.
  28. //   2. Use fitBspline to build cubic splines which interpolate
  29. //        the points of the degree 1 curves.
  30. //   3. Use loft to build a surface through these cubic curves.
  31. // 
  32. // Usage hints:
  33. //  - Using a larger number of samples increases accuracy, but can get
  34. //      very slow. Try with 1 first, then increase as needed.
  35. //  - If the surface is periodic, try to have it periodic in U rather
  36. //      than V for best results. The reverseSurface 'swap' option can be
  37. //      used for this. One example where this is needed is for revolved
  38. //      surfaces, since these are created periodic in V, so should be
  39. //      swapped before offsetting. If the original surface is periodic in
  40. //      U, the offset surface will also be created periodic in U.
  41. //
  42. // Deficiencies:
  43. //   This is by no means an industrial strength surface offset.
  44. //   For example:
  45. //    - there is no check for self-intersection in the resulting
  46. //        offset surface, surfaces with sharp corners are unlikely to
  47. //        offset well, etc.
  48. //    - offsets of surfaces which are periodic in V, or closed in
  49. //      either direction can have kinks. For periodic surfaces, having
  50. //      the surface periodic in U rather than V will help.
  51. //    - Can be very slow for large surfaces or large numbers of samples.
  52. //    - as with all offsets, it works best if the offset distance is
  53. //        small relative to the size of the object.
  54. //
  55. // Author: MPW
  56. //
  57. //    This is an unsupported script, so use at your own risk.
  58. //
  59. proc int getNurbsSurfaceKnots(string $srfName, float $uKnots[], float $vKnots[] )
  60. //
  61. //    Description :
  62. //    Get surface knots in U and V
  63. {
  64.  
  65.     // create info Node.
  66.     string $infoNode ;
  67.     if( catch( $infoNode = `createNode surfaceInfo` ) ) {
  68.         return 1; // failed
  69.     } 
  70.  
  71.     // connect surface on to the info node.
  72.     string $outAttr = $srfName + ".local" ; 
  73.     string $inAttr = $infoNode + ".is" ;
  74.     connectAttr $outAttr $inAttr ;
  75.  
  76.     // read the knots.
  77.     $uKnots = `getAttr ($infoNode + ".knotsU")`;    
  78.     $vKnots = `getAttr ($infoNode + ".knotsV")`;    
  79.  
  80.     // delete surface info node.
  81.     delete $infoNode ;
  82.  
  83.     // worked
  84.     return 0;
  85. }
  86.  
  87. proc int getNurbsSurfaceOffset( 
  88.     string $srf, float $distance, int $samplesPerSpan)
  89. //
  90. //    Description :
  91. //    Compute offset surface by computing points 
  92. //  regularly spaced in U and V on the surface, fitting curves
  93. //  and then lofting a surface through the curves.
  94. // 
  95. {
  96.     int $i; // loop counter
  97.  
  98.     // number of spans
  99.     int $nspansU = eval("getAttr " + $srf + ".spansU");
  100.     int $nspansV = eval("getAttr " + $srf + ".spansV");
  101.  
  102.     // degree
  103.     int $degreeU = eval("getAttr " + $srf + ".degreeU");
  104.     int $degreeV = eval("getAttr " + $srf + ".degreeV");
  105.  
  106.     // knots
  107.     float $uKnots[];
  108.     float $vKnots[];
  109.     if(getNurbsSurfaceKnots($srf, $uKnots, $vKnots)) {
  110.         return 1; // failed
  111.     }
  112.  
  113.     // first and last knot values to use 
  114.     int $firstU = $degreeU - 1;
  115.     int $lastU = $nspansU + $firstU;
  116.     int $firstV = $degreeV - 1;
  117.     int $lastV = $nspansV + $firstV;
  118.  
  119.     // loop over knot values
  120.     int $uIndex, $vIndex;
  121.     int $uSample, $vSample;
  122.     int $uSampleMax, $vSampleMax;
  123.     float $u, $v;
  124.  
  125.     string $allCurves;
  126.  
  127.     // check if periodic in U. If so, dont need to evaluate last U
  128.     // isoparm on surface since it is coincident with the first
  129.     int $formInU = eval("getAttr " + $srf + ".formU");
  130.  
  131.     // loop over U spans
  132.     for($uIndex = $firstU; $uIndex < $lastU; $uIndex++) {
  133.  
  134.         // maximum number of samples for this span
  135.         $uSampleMax = ($formInU == 2 || $uIndex < $lastU-1) ? $samplesPerSpan - 1 : $samplesPerSpan;
  136.  
  137.         // parameter interval for this span
  138.         float $uInterval = $uKnots[$uIndex+1] - $uKnots[$uIndex];
  139.  
  140.         // loop over U samples
  141.         for($uSample = 0; $uSample <= $uSampleMax; $uSample++) {
  142.  
  143.             // get value of U
  144.             $u = $uKnots[$uIndex] + $uSample*$uInterval/float($samplesPerSpan);
  145.             // make sure rouding errors dont take it off the end
  146.             if($uIndex == ($formInU == 2 || $lastU-1) && $uSample == $uSampleMax) {
  147.                 $u = $uKnots[$lastU];
  148.             }
  149.  
  150.             // make a degree 1 curve passing through these offset points
  151.             string $curveCmd = "curve -d 1";
  152.  
  153.             // loop over V spans
  154.             for($vIndex = $firstV; $vIndex < $lastV; $vIndex++) {
  155.  
  156.                 // maximum number of samples for this span
  157.                 $vSampleMax = ($vIndex < $lastV-1) ? $samplesPerSpan - 1 : $samplesPerSpan;
  158.                 // parameter interval for this span
  159.                 float $vInterval = $vKnots[$vIndex+1] - $vKnots[$vIndex];
  160.  
  161.                 // loop over V samples
  162.                 for($vSample = 0; $vSample <= $vSampleMax; $vSample++) {
  163.  
  164.                     $v = $vKnots[$vIndex] + $vSample*$vInterval/float($samplesPerSpan);
  165.                     // make sure rouding errors dont take it off the end
  166.                     if($vIndex == ($lastV-1) && $vSample == $vSampleMax) {
  167.                         $v = $vKnots[$lastV];
  168.                     }
  169.  
  170.                     // compute the surface point
  171.                     float $pos[] = eval ("pointOnSurface -u " + $u + " -v " + $v + " -top false -p " + $srf);
  172.                     float $norm[] = eval ("pointOnSurface -u " + $u + " -v " + $v + " -top false -n " + $srf);
  173.  
  174.                     // adjust normal for the offset distance required
  175.                     float $scaling = $distance / sqrt($norm[0]*$norm[0] + $norm[1]*$norm[1] + $norm[2]*$norm[2]);
  176.                     
  177.                     float $offsetPos[3];
  178.                     for($i=0; $i<3; $i++) { 
  179.                         $offsetPos[$i] = $pos[$i] + $scaling*$norm[$i];
  180.                     }
  181.                     //print ("Position at uv " + $u + " " + $v + " is " + $pos[0] + " " + $pos[1] + " " + $pos[2] + "\n");
  182.                     //print ("Normal at uv " + $u + " " + $v + " is " + $norm[0] + " " + $norm[1] + " " + $norm[2] + "\n");
  183.                     //print ("Offset at uv " + $u + " " + $v + " is " + $offsetPos[0] + " " + $offsetPos[1] + " " + $offsetPos[2] + "\n");
  184.  
  185.                     string $pt = (" -p " + $offsetPos[0] + " " + $offsetPos[1] + " " + $offsetPos[2]);
  186.                     $curveCmd += $pt;
  187.                 }
  188.             }
  189.             //print ("Curve cmd is " + $curveCmd);
  190.             string $deg1crv = eval($curveCmd);
  191.             string $deg3crv[];
  192.             if(catch($deg3crv = eval("fitBspline -ch 0 -tol 0.0001 " + $deg1crv))) {
  193.                 // unable to fit spline, maybe degenerate points. Use degree 1 curve instead
  194.                 print ("Ignore above error - everything is under control\n");
  195.                 $allCurves += " " + $deg1crv;
  196.             } else {
  197.                 // worked - take degree 3 curve
  198.                 $allCurves += " " + $deg3crv[0];
  199.                 delete $deg1crv;
  200.             }
  201.         }
  202.     }
  203.     //print ("All curves are: " + $allCurves + "\n");
  204.     // now loft the curves
  205.     string $loftCmd = "loft -ch 0 -d 3 ";
  206.     if($formInU == 2) $loftCmd += " -c on ";
  207.     $loftCmd += $allCurves;
  208.     //print("Loft command is " + $loftCmd + "\n");
  209.  
  210.     // close flag - check basic surface first...
  211.      string $outsrf[] = eval($loftCmd);
  212.      print ("Created offset surface " + $outsrf[0] + "\n");
  213.  
  214.      // delete all input curves
  215.        eval("delete " + $allCurves);
  216.  
  217.     // return the surface name??
  218.     return 0;
  219. }
  220.  
  221.  
  222. global proc offsetSurfaceUsingLoft(float $distance, int $samplesPerSpan)
  223. {
  224.     // Run filter to select only the NURBS surfaces
  225.     global int $gSelectNurbsSurfacesBit ;
  226.     string $srfList[] = `filterExpand -ex true 
  227.         -sm $gSelectNurbsSurfacesBit`;
  228.     int $len = size($srfList) ;
  229.     if( $len == 0 ) {
  230.         print "No NURBS surfaces selected\n" ;
  231.         return;
  232.     }
  233.  
  234.     // always need at least one sample per span
  235.     if($samplesPerSpan < 1) $samplesPerSpan = 1;
  236.  
  237.     // Work on all surfaces
  238.     for($srfNum = 0; $srfNum < $len; $srfNum++) {
  239.         string $srf = $srfList[$srfNum] ;
  240.  
  241.         // do the offset
  242.         if(getNurbsSurfaceOffset($srf, $distance, $samplesPerSpan)) {
  243.             print ("Failed to compute box for surface " + $srf + "\n");
  244.             break;
  245.         }
  246.     }
  247.  
  248. }
  249.